<template>
  <view
    :class="`wd-col-picker ${cell.border.value ? 'is-border' : ''} ${customClass}`"
    :style="customStyle"
  >
    <view class="wd-col-picker__field" @click="showPicker">
      <slot v-if="useDefaultSlot"></slot>
      <view
        v-else
        :class="`wd-col-picker__cell ${disabled && 'is-disabled'} ${readonly && 'is-readonly'} ${alignRight && 'is-align-right'} ${
          error && 'is-error'
        }  ${size && 'is-' + size}`"
      >
        <view
          v-if="label || useLabelSlot"
          :class="`wd-col-picker__label ${isRequired && 'is-required'} ${customLabelClass}`"
          :style="labelWidth ? 'min-width:' + labelWidth + ';max-width:' + labelWidth + ';' : ''"
        >
          <block v-if="label">{{ label }}</block>
          <slot v-else name="label"></slot>
        </view>
        <view class="wd-col-picker__body">
          <view class="wd-col-picker__value-wraper">
            <view
              :class="`wd-col-picker__value ${ellipsis && 'is-ellipsis'} ${customValueClass} ${showValue ? '' : 'wd-col-picker__value--placeholder'}`"
            >
              {{ showValue || placeholder || '请选择' }}
            </view>
            <wd-icon
              v-if="!disabled && !readonly"
              custom-class="wd-col-picker__arrow"
              name="arrow-right"
            />
          </view>
          <view v-if="errorMessage" class="wd-col-picker__error-message">{{ errorMessage }}</view>
        </view>
      </view>
    </view>
    <!--  :title="title || '请选择'" -->
    <wd-action-sheet
      v-model="pickerShow"
      :duration="250"
      :close-on-click-modal="closeOnClickModal"
      :z-index="zIndex"
      :safe-area-inset-bottom="safeAreaInsetBottom"
      @open="handlePickerOpend"
      @close="handlePickerClose"
    >
      <view class="pop_t flex" style="padding: 40rpx 40rpx 20rpx 40rpx">
        <view class="close" style="color: cornflowerblue" @click="reset">重置</view>
        <view
          class="title_name flex-1"
          style="text-align: center; font-size: 28rpx; justify-content: center"
        >
          请选择
        </view>
        <view class="close" style="color: cornflowerblue" @click="handleConfirm">确定</view>
      </view>
      <wd-search
        placeholder="请输入分类名"
        cancel-txt="搜索"
        v-model="typeName"
        @search="searchHandle"
        @cancel="searchHandle"
      ></wd-search>
      <view class="wd-col-picker__selected">
        <scroll-view :scroll-x="true" scroll-with-animation :scroll-left="scrollLeft">
          <view class="wd-col-picker__selected-container">
            <view class="wd-col-picker__selected-item is-selected">
              {{ selectShowList[0] || '请选择' }}
            </view>
            <view class="wd-col-picker__selected-line" :style="lineStyle"></view>
          </view>
        </scroll-view>
      </view>
      <view class="wd-col-picker__list-container">
        <view class="flex">
          <view
            v-for="(col, colIndex) in selectList"
            :key="colIndex"
            :class="`wd-col-picker__list ${colIndex == 1 && 'flex-1'}`"
          >
            <scroll-view
              scroll-y
              :scroll-top="colIndex == 1 ? translate : 0"
              :style="showSecond || colIndex == 0 ? 'display: block;' : 'display: none;'"
            >
              <view
                v-for="(item, index) in col"
                :key="index"
                :class="`wd-col-picker__list-item ${pickerColSelected[colIndex] && item[valueKey] === pickerColSelected[colIndex] && 'is-selected'} ${
                  item.disabled && 'is-disabled'
                }`"
                @click="chooseItem(colIndex, index)"
              >
                <view>
                  <view class="wd-col-picker__list-item-label">{{ item[labelKey] }}</view>
                  <view v-if="item[tipKey]" class="wd-col-picker__list-item-tip">
                    {{ item[tipKey] }}
                  </view>
                </view>
                <wd-icon custom-class="wd-col-picker__checked" name="check"></wd-icon>
              </view>
            </scroll-view>

            <view v-if="loading" class="wd-col-picker__loading">
              <wd-loading :color="loadingColor" />
            </view>
          </view>

          <!-- <view class="flex-1" v-if="colIndex === currentCol">
            <view v-for="(item, index) in col[colIndex]" :key="index" @click="chooseItem(colIndex)">
              <view>
                <view class="wd-col-picker__list-item-label">{{ item[labelKey] }}</view>
                <view v-if="item[tipKey]" class="wd-col-picker__list-item-tip">
                  {{ item[tipKey] }}
                </view>
              </view>
              <wd-icon custom-class="wd-col-picker__checked" name="check"></wd-icon>
            </view>
          </view> -->
        </view>
      </view>
    </wd-action-sheet>
  </view>
</template>
<script lang="ts">
export default {
  name: 'wd-col-picker',
  options: {
    addGlobalClass: true,
    virtualHost: true,
    styleIsolation: 'shared',
  },
};
</script>

<script lang="ts" setup>
import { computed, getCurrentInstance, onMounted, ref, watch } from 'vue';
import { debounce, getRect, isArray, isBoolean, isFunction } from '../common/util';
import { useCell } from '../composables/useCell';
// import { FORM_KEY, type FormItemRule } from '../wd-form/types';
import { useParent } from '../composables/useParent';
// import { useTranslate } from '../composables/useTranslate';
import { colPickerProps, type ColPickerExpose } from './types';
const FORM_KEY: InjectionKey<FormProvide> = Symbol('wd-form');
// const { translate } = useTranslate('col-picker');

const $container = '.wd-col-picker__selected-container';
const $item = '.wd-col-picker__selected-item';

const props = defineProps(colPickerProps);
const emit = defineEmits(['close', 'update:modelValue', 'confirm']);
const typeName = ref('');
const pickerShow = ref<boolean>(false);
const currentCol = ref<number>(0);
const selectList = ref<Record<string, any>[][]>([]);
const pickerColSelected = ref<(string | number)[]>([]);
const selectShowList = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false);
const isChange = ref<boolean>(false);
const lastSelectList = ref<Record<string, any>[][]>([]);
const lastPickerColSelected = ref<(string | number)[]>([]);
const lineStyle = ref<string>('');
const scrollLeft = ref<number>(0);
const inited = ref<boolean>(false);
const isCompleting = ref<boolean>(false);
const { proxy } = getCurrentInstance() as any;

const cell = useCell();

const updateLineAndScroll = debounce(function (animation = true) {
  setLineStyle(animation);
  lineScrollIntoView();
}, 50);

const showValue = computed(() => {
  const selectedItems = (props.modelValue || []).map((item, colIndex) => {
    return getSelectedItem(item, colIndex, selectList.value);
  });

  if (props.displayFormat) {
    return props.displayFormat(selectedItems);
  } else {
    return selectedItems
      .map((item) => {
        return item[props.labelKey];
      })
      .join('');
  }
});

watch(
  () => props.modelValue,
  (newValue) => {
    if (newValue === pickerColSelected.value) return;
    pickerColSelected.value = newValue;
    newValue.map((item, colIndex) => {
      return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
    });
    handleAutoComplete();
  },
  {
    deep: true,
    immediate: true,
  },
);

watch(
  () => props.columns,
  (newValue, oldValue) => {
    if (newValue.length && !isArray(newValue[0])) {
      console.error(
        '[wot design] error(wd-col-picker): the columns props of wd-col-picker should be a two-dimensional array',
      );
      return;
    }
    if (newValue.length === 0 && !oldValue) return;

    const newSelectedList = newValue.slice(0);

    selectList.value = newSelectedList;

    // selectShowList.value = pickerColSelected.value.map((item, colIndex) => {
    //   return getSelectedItem(item, colIndex, newSelectedList)[props.labelKey];
    // });
    lastSelectList.value = newValue;

    if (newSelectedList.length > 0) {
      currentCol.value = newSelectedList.length - 1;
    }
  },
  {
    deep: true,
    immediate: true,
  },
);
const transArr = (arr, list = []) => {
  arr.map((item) => {
    list.push(item);
    if (item.children && item.children.length > 0) {
      transArr(item.children, list);
    }
  });
  return list;
};

const translate = ref(0);
const searchHandle = (e) => {
  if (!e.value) {
    reset();
    return;
  }
  showSecond.value = true;
  const { valueKey, labelKey } = props;
  let flatArray = transArr(selectList.value[0]).filter((item) => item[valueKey].length == 4);

  if (pickerColSelected.value.length) {
    flatArray = flatArray.filter(
      (item) => item[valueKey].substr(0, 2) == pickerColSelected.value[0],
    );
  }
  const curr = flatArray.find((item) => item[labelKey].includes(e.value));

  if (curr) {
    const cI = selectList.value[0].findIndex(
      (item) => item[valueKey] == curr[valueKey].slice(0, 2),
    );
    const secIndex = selectList.value[0][cI].children.findIndex(
      (item) => item[valueKey] == curr[valueKey],
    );
    pickerColSelected.value = [];
    if (cI > -1) {
      nextTick(() => {
        currColIndex.value = 0;
        currIndex.value = cI;
        // currentCol.value = cI;
        pickerColSelected.value.push(curr[valueKey].slice(0, 2));
        setTimeout(() => {
          chooseItem(0, cI);
          pickerColSelected.value.push(curr[valueKey]);
          translate.value = secIndex * 42;
          handleAutoComplete();
        }, 10);
        // pickerColSelected.value.map((item, colIndex) => {
        //   return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
        // });
      });
    } else {
      pickerColSelected.value[0] = '';
      pickerColSelected.value[1] = '';
    }
  }
};
watch(
  () => props.columnChange,
  (fn) => {
    if (fn && !isFunction(fn)) {
      console.error('The type of columnChange must be Function');
    }
  },
  {
    deep: true,
    immediate: true,
  },
);

watch(
  () => props.displayFormat,
  (fn) => {
    if (fn && !isFunction(fn)) {
      console.error('The type of displayFormat must be Function');
    }
  },
  {
    deep: true,
    immediate: true,
  },
);

watch(
  () => props.beforeConfirm,
  (fn) => {
    if (fn && !isFunction(fn)) {
      console.error('The type of beforeConfirm must be Function');
    }
  },
  {
    deep: true,
    immediate: true,
  },
);

const { parent: form } = useParent(FORM_KEY);

// 表单校验错误信息
const errorMessage = computed(() => {
  if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
    return form.errorMessages[props.prop];
  } else {
    return '';
  }
});

// 是否展示必填
const isRequired = computed(() => {
  let formRequired = false;
  if (form && form.props.rules) {
    const rules = form.props.rules;
    for (const key in rules) {
      if (
        Object.prototype.hasOwnProperty.call(rules, key) &&
        key === props.prop &&
        Array.isArray(rules[key])
      ) {
        formRequired = rules[key].some((rule: FormItemRule) => rule.required);
      }
    }
  }
  return props.required || props.rules.some((rule) => rule.required) || formRequired;
});

onMounted(() => {
  inited.value = true;
});

// 打开弹框
function open() {
  showPicker();
}
// 关闭弹框
function close() {
  handlePickerClose();
}
function handlePickerOpend() {
  updateLineAndScroll(false);
}

function handlePickerClose() {
  pickerShow.value = false;
  // 如果目前用户正在选择，需要在popup关闭时将数据重置回上次数据，popup 关闭时间 250
  if (isChange.value) {
    setTimeout(() => {
      selectList.value = lastSelectList.value.slice(0);
      pickerColSelected.value = lastPickerColSelected.value.slice(0);
      selectShowList.value = lastPickerColSelected.value.map((item, colIndex) => {
        return getSelectedItem(item, colIndex, lastSelectList.value)[props.labelKey];
      });
      currentCol.value = lastSelectList.value.length - 1;
      isChange.value = false;
    }, 250);
  }
  emit('close');
}
function showPicker() {
  const { disabled, readonly } = props;
  typeName.value = '';
  showSecond.value = true;
  if (disabled || readonly) return;
  pickerShow.value = true;
  lastPickerColSelected.value = pickerColSelected.value.slice(0);
  lastSelectList.value = selectList.value.slice(0);
}

function getSelectedItem(
  value: string | number,
  colIndex: number,
  selectList: Record<string, any>[][],
) {
  const { valueKey, labelKey } = props;
  if (selectList[colIndex]) {
    const selecteds = selectList[colIndex].filter((item) => {
      return item[valueKey] === value;
    });

    if (selecteds.length > 0) {
      return selecteds[0];
    }
  }

  return {
    [valueKey]: value,
    [labelKey]: '',
  };
}
const currColIndex = ref(-1);
const currIndex = ref(-1);
const currItem = ref(null);

function chooseItem(colIndex: number, index: number) {
  showSecond.value = true;
  currColIndex.value = colIndex;
  currIndex.value = index;
  const item = selectList.value[colIndex][index];
  if (item.disabled) return;
  currItem.value = item;
  const newPickerColSelected = pickerColSelected.value.slice(0, colIndex);
  newPickerColSelected.push(item[props.valueKey]);
  isChange.value = true;
  pickerColSelected.value = newPickerColSelected;
  selectList.value = selectList.value.slice(0, colIndex + 1);
  selectShowList.value = newPickerColSelected.map((item, colIndex) => {
    return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
  });
  handleColChange(colIndex, item, index);
}
const showSecond = ref(true);
const reset = () => {
  pickerColSelected.value = [];
  selectShowList.value = [];
  lastPickerColSelected.value = pickerColSelected.value.slice(0);
  lastSelectList.value = selectList.value.slice(0);
  showSecond.value = false;
  // emit('update:modelValue', []);
  // emit('confirm', {
  //   value: [],
  //   selectedItems: '全部',
  // });
};
const handleConfirm = () => {
  if (pickerColSelected.value.length == 0) {
    isChange.value = false;
    loading.value = false;
    pickerShow.value = false;
    emit('update:modelValue', []);
    emit('confirm', {
      value: [],
      selectedItems: [],
    });
    return;
  }
  onConfirm();
};
function handleColChange(
  colIndex: number,
  item: Record<string, any>,
  index: number,
  callback?: () => void,
) {
  loading.value = true;
  const { columnChange, beforeConfirm } = props;
  columnChange &&
    columnChange({
      selectedItem: item,
      index: colIndex,
      rowIndex: index,
      resolve: (nextColumn: Record<string, any>[]) => {
        if (!isArray(nextColumn)) {
          console.error(
            '[wot design] error(wd-col-picker): the data of each column of wd-col-picker should be an array',
          );
          return;
        }

        const newSelectList = selectList.value.slice(0);
        newSelectList[colIndex + 1] = nextColumn;

        selectList.value = newSelectList;
        loading.value = false;
        currentCol.value = colIndex + 1;

        updateLineAndScroll(true);
        if (typeof callback === 'function') {
          isCompleting.value = false;
          selectShowList.value = pickerColSelected.value.map((item, colIndex) => {
            return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
          });
          callback();
        }
      },
      finish: (isOk?: boolean) => {
        // 每设置展示数据回显
        if (typeof callback === 'function') {
          loading.value = false;
          isCompleting.value = false;
          return;
        }
        if (isBoolean(isOk) && !isOk) {
          loading.value = false;
          return;
        }

        if (beforeConfirm) {
          beforeConfirm(
            pickerColSelected.value,
            pickerColSelected.value.map((item, colIndex) => {
              return getSelectedItem(item, colIndex, selectList.value);
            }),
            (isPass: boolean) => {
              if (isPass) {
                onConfirm();
              } else {
                loading.value = false;
              }
            },
          );
        } else {
          onConfirm();
        }
      },
    });
}
function onConfirm() {
  isChange.value = false;
  loading.value = false;
  pickerShow.value = false;

  emit('update:modelValue', pickerColSelected.value);
  emit('confirm', {
    value: pickerColSelected.value,
    selectedItems: pickerColSelected.value.map((item, colIndex) => {
      return getSelectedItem(item, colIndex, selectList.value);
    }),
  });
}
function handleColClick(index: number) {
  isChange.value = true;
  currentCol.value = index;
  updateLineAndScroll(true);
}
/**
 * @description 更新navBar underline的偏移量
 * @param {Boolean} animation 是否伴随动画
 */
function setLineStyle(animation = true) {
  if (!inited.value) return;
  getRect($item, true, proxy).then((rects) => {
    const rect = rects[currentCol.value];
    // const width = lineWidth || (slidableNum < items.length ? rect.width : (rect.width - 14))
    if (rect) {
      const width = 16;
      let left = rects
        .slice(0, currentCol.value)
        .reduce((prev: any, curr: any) => prev + curr.width, 0);
      left += (Number(rect.width) - width) / 2;
      const transition = animation ? 'transition: width 300ms ease, transform 300ms ease;' : '';

      const lineStyleTemp = `
          transform: translateX(${left}px);
          ${transition}
        `;
      // 防止重复绘制
      if (lineStyle.value !== lineStyleTemp) {
        lineStyle.value = lineStyleTemp;
      }
    }
  });
}
/**
 * @description scroll-view滑动到active的tab_nav
 */
function lineScrollIntoView() {
  if (!inited.value) return;
  Promise.all([getRect($item, true, proxy), getRect($container, false, proxy)]).then(
    ([navItemsRects, navRect]) => {
      if (!isArray(navItemsRects) || navItemsRects.length === 0) return;
      // 选中元素
      const selectItem = navItemsRects[currentCol.value];
      // 选中元素之前的节点的宽度总和
      if (selectItem) {
        const offsetLeft = navItemsRects
          .slice(0, currentCol.value)
          .reduce((prev, curr) => prev + Number(curr.width), 0);
        // scroll-view滑动到selectItem的偏移量
        scrollLeft.value = offsetLeft - ((navRect as any).width - Number(selectItem.width)) / 2;
      }
    },
  );
}

// 递归列数据补齐
function diffColumns(colIndex: number) {
  // colIndex 为 -1 时，item 为空对象，>=0 时则具有 value 属性
  const item = colIndex === -1 ? {} : { [props.valueKey]: props.modelValue[colIndex] };
  handleColChange(colIndex, item, -1, () => {
    // 如果 columns 长度还小于 value 长度，colIndex + 1，继续递归补齐
    if (selectList.value.length < props.modelValue.length) {
      diffColumns(colIndex + 1);
    }
  });
}
function handleAutoComplete() {
  if (props.autoComplete) {
    // 如果 columns 数组长度为空，或者长度小于 value 的长度，自动触发 columnChange 来补齐数据
    if (selectList.value.length < props.modelValue.length || selectList.value.length === 0) {
      // isCompleting 是否在自动补全，锁操作
      if (!isCompleting.value) {
        // 如果 columns 长度为空，则传入的 colIndex 为 -1
        const colIndex = selectList.value.length === 0 ? -1 : selectList.value.length - 1;
        diffColumns(colIndex);
      }
      isCompleting.value = true;
    }
  }
}

defineExpose<ColPickerExpose>({
  close,
  open,
});
</script>

<style lang="scss" scoped>
@import './index.scss';
.flex {
  display: flex;
}
.flex-1 {
  flex: 1;
}
.flex-3 {
  flex: 3;
}
.wd-col-picker__list {
  min-width: 33.3%;
}
</style>
